import { Ast, createRootAst } from "./ast";
import { CoreVisitor } from "./core";
import { clickSend } from "./red/send";
import { formatMinute, swipeUpV3 } from "./utils";

class RedPacketContext {
    startTime: number = new Date().getTime();

    title: string;
    type: string;
    subType: string;
    action: Ast;
    message: string;
    isFinish: boolean = false;
    isJoin: boolean = false;
    count: number = 0;
    fail: string;

    waitTime: number = -1;

    redWaitReg: RegExp = /(.*?)后开奖/;

    redTotal: number;
    redCount: number;
    redUnit: string;

    constructor(private parent: WaitRedOpenContext) { }
    x: number;
    y: number;
    setPosition(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    checkFinish() {
        if (this.waitTime > -1) {
            if (this.waitTime === 0) {
                this.isFinish = true;
            }
            if ((new Date().getTime() - this.startTime) > (this.waitTime * 1000 + 10 * 1000)) {
                this.isFinish = true;
            }
        }
    }

    setCount(count: number) {
        if (count) this.count = count;
        this.isFinish = true;
        this.parent.log(`恭喜您中了${count}快币`)
    }
    setFail(text: string) {
        this.fail = text;
        this.isFinish = true;
        this.parent.log(text)
    }
    setAction(action: Ast) {
        this.action = action;
    }
    /**
     * 参与红包
     */
    join() {
        if (this.action) {
            this.action.click()
            if (this.type === '口令') {
                sleep(5000)
                clickSend(this.parent)
            }
            this.isJoin = true;
            this.parent.log(`成功参与${this.title}`)
        }
    }

    setWait(text?: string) {
        if (!text) {
            this.message = `等待开奖`;
            this.isJoin = true;
            this.startTime = new Date().getTime();
            this.waitTime = 3;
            return;
        }
        if (this.message !== text) {
            this.message = text;
            // 提取出时间 然后按时间排序
            const res = text.match(this.redWaitReg)
            if (res && res.length > 0) {
                this.isJoin = true;
                const [, waitTime] = res;
                this.startTime = new Date().getTime();
                if (waitTime.endsWith('分钟')) {
                    this.waitTime = (parseInt(waitTime.replace('分钟', '')) + 1) * 60;
                }
                if (waitTime.endsWith('秒')) {
                    this.waitTime = parseInt(waitTime.replace('秒', ''))
                }
            }
        }
    }
    setTitle(title: string) {
        this.title = title;
        if (title && title.length > 0) {
            const res = this.title.match(/主播的(.*?)红包/)
            if (res && res.length > 0) {
                const [, type] = res;
                this.type = type;
            } else if (/.*?穿云箭.*?/.test(this.title)) {
                this.type = `穿云箭`
            } else if (/.*?春季盛典红包/.test(this.title)) {
                this.type = `春季盛典`
            } else if (/.*?的快币红包.*?/.test(this.title)) {
                // 主播的快币红包和观众包
                this.type = '快币'
            } else if (/.*?礼物红包.*?/.test(this.title)) {
                this.type = `礼物`
            } else {
                this.type = `其他`
            }
        }
    }
}
class WaitRedOpenContext {
    dbclickNode: Ast;
    // 开始时间
    startTime: number = new Date().getTime()

    // 总超时时间
    timeout: number = 0;
    /**
     * 打开红包参数
     */
    openTimeout: number = 0;
    // 打开红包的时间
    openTime: number = 0;
    // 是否打开成功
    openSuccess: boolean = false;
    // 打开红包超时
    isOpenTimeout: boolean = false;

    /**
     * 参加红包参数
     */
    // 参加活动超时
    isJoinTimeout: boolean = false;
    // 参加活动超时
    joinTimeout: number = 0;
    // 参加时间
    joinTime: number = 0;

    // 抢包超时
    isTimeout: boolean = false;

    // 红包个数
    redCount: number = 0;

    /**
     * 房间红包
     */
    redPackets: RedPacketContext[] = [];
    /**
     * 红包类型
     */
    types: string[] = [];
    /**
     * 中奖金额
     */
    count: number = 0;

    /**
     * 是否失败
     */
    isFail: boolean = false;

    /**
     * 此房间没有红包
     */
    noRedPacket: boolean = false;

    message: string;

    closeNode: Ast;
    /**
     * 直播已结束
     * 是否关闭
     */
    isClosed: boolean = false;
    /**
     * 人为停止
     * 程序停止
     */
    isStop: boolean = false;

    /**
     * 开奖超时
     */
    redOpenTimeout: number;
    // 在线人数
    online: number;

    logger: Function;
    constructor(types: string[], timeout: number = 1000 * 60 * 10, openTimeout: number = 1000 * 60, joinTimeout: number = 1000 * 60 * 2) {
        this.timeout = timeout;
        this.openTimeout = openTimeout;
        this.joinTimeout = joinTimeout;
        this.types = types;
        this.log(`房间超时: ${formatMinute(this.timeout / 1000)} 打开超时：${formatMinute(this.openTimeout / 1000)} 参与超时：${formatMinute(this.joinTimeout)}`)
    }
    leftJoinTime: number = new Date().getTime();
    leftOpenTime: number = new Date().getTime();
    openNode: Ast;

    noRed: boolean = false;
    setOpenTime(text: string) {
        if (text === `进行中`) {
            // 没有红包
            this.noRed = true;
            return;
        }
        if (text === `抢红包`) {
            this.leftJoinTime = 0;
            return;
        }
        const texts = text.split(':');
        if (texts.length == 2) {
            const [minute, second] = texts;
            this.leftOpenTime = parseInt(minute) * 60 + parseInt(second);
        }
    }
    setLogger(logger: Function) {
        this.logger = logger;
    }
    target: LiveRoomJoinAndWaitRedOpen;
    setTarget(t: LiveRoomJoinAndWaitRedOpen) {
        this.target = t;
    }
    getOtherCondiction() {
        return this.target.getOtherCondiction()
    }
    setClose(text: string) {
        this.isClosed = true;
        this.log(text)
    }
    setStop(stop: boolean) {
        this.isStop = stop;
    }
    isFinish(): boolean {
        // 其他因素停止
        if (this.isStop) return true;
        // 如果直播已结束 则停止
        if (this.isClosed) return true;
        // 如果没有红包 则停止 【进行中】
        // if (this.noRedPacket) return true;
        if (this.shouldFinish()) {
            this.isTimeout = true;
            this.setMessage(`房间超时`)
            return true;
        }
        // 总共等待 已超时 则停止
        if (this.hasTimeout()) {
            this.isTimeout = true;
            this.setMessage(`等待开包超时`)
            return true;
        }
        // 还没有打开红包
        if (this.hasOpenTimeout()) {
            this.isOpenTimeout = true;
            this.setMessage(`打开红包超时`)
            return true;
        }
        // 是否参加活动
        if (this.hasJoinTimeout()) {
            this.isJoinTimeout = true;
            this.setMessage(`参与红包超时`)
            return true;
        }
        /**
         * 检查是否满足开包条件
         */
        if (this.canJoinRedPacket()) {
            this.openRedPacket()
            return false;
        }

        if (this.joinRedPacket()) {
            return true;
        }

        if (this.noRed) {
            return true;
        }

        const joinRedPackets = this.redPackets.filter(it => it.isJoin)
        if (joinRedPackets.length > 0) {
            this.redTime = new Date().getTime()
            if (joinRedPackets.every(it => it.isFinish)) {
                return true;
            }
        } else {
            if (this.openTime > 0 && (new Date().getTime() - this.openTime) > 1000 * 60 * 1) {
                this.setMessage(`参加红包超时`)
                return true;
            }
        }
        return false;
    }
    /**
     * 是否可以参加红包
     */
    // 开包时间
    minOpenTime: number = 30;
    // 进入房间时间
    minJoinTime: number = 30;
    maxMoneyV: number = 0.5;

    shouldFinish() {
        const dec = new Date().getTime() - this.startTime - 15 * 1000
        if (dec > this.minJoinTime * 1000) {
            return true;
        }
        return false;
    }

    canJoinRedPacket() {
        if (this.openSuccess) {
            return false;
        }
        if (this.openNode && this.leftOpenTime <= this.minOpenTime) {
            return true;
        }
        // 双击屏幕
        this.dbclickNode?.clickRect()
        this.dbclickNode?.clickRect()
        return false;
    }
    redTime: number = new Date().getTime()
    /**
     * 判断是否参加超时
     * @returns 
     */
    private hasJoinTimeout() {
        // 还没有打开 直接返回 false
        if (!this.openTime) return false;
        // 已经参加成功 返回false
        if (this.joinTime) return false;
        const dec = new Date().getTime() - this.openTime;
        return dec >= this.joinTimeout;
    }
    /**
     * 总体超时
     * @returns 
     */
    private hasTimeout() {
        const dec = new Date().getTime() - this.startTime;
        return dec >= this.timeout;
    }
    /**
     * 打开超时
     * @returns 
     */
    private hasOpenTimeout() {
        if (this.openSuccess) return false;
        const dec = new Date().getTime() - this.startTime;
        return dec >= this.openTimeout;
    }
    /**
     * 打开红包
     */
    openRedPacket() {
        if (this.openNode) {
            if (this.openNode.clickable) {
                this.openNode.click()
                this.openNode = null;
            } else {
                this.openNode.clickRect()
                this.openNode = null;
            }
        }
        this.openSuccess = true;
        this.openTime = new Date().getTime()
        this.setMessage(`成功打开房间红包弹框`)
    }
    /**
     * 参加红包
     * 返回true 则不参加 
     */
    joinSuccess: boolean = false;
    joinRedPacket() {
        const redPacket = this.redPackets.find(it => this.types.includes(it.type) && !it.isJoin)
        if (redPacket) {
            // 检查是否满足条件
            if (!redPacket.redCount) {
                return false;
            }
            let moneyV = redPacket.redCount / this.online;
            if (redPacket.type === '粉丝团') {
                this.log(`暂不支持粉丝团`)
                return true;
            }
            if (moneyV >= this.maxMoneyV) {
                if (redPacket.subType && redPacket.subType === '观众包') {
                    click(redPacket.x, redPacket.y)
                    click(redPacket.x, redPacket.y)
                    return false;
                } else {
                    redPacket.join();
                }
                this.joinTime = new Date().getTime();
                this.log(`【${redPacket.redCount}/${this.online}>${this.maxMoneyV}】满足条件，参与成功`)
                this.joinSuccess = true;
                sleep(1000 * 3)
                return false;
            }
            this.log(`【${redPacket.redCount}/${this.online}>${this.maxMoneyV}】不满足条件，不参与退出房间`)
            sleep(1000 * 3)
            return true;
        }
        return false;
    }
    setRedCount(count: number) {
        this.redCount = count;
        if (count === 0) {
            this.setNoRedPacket()
        }
    }
    /**
     * 添加红包
     * @param redPacket 红包信息
     */
    addRedPacket(redPacket: RedPacketContext) {
        const item = this.redPackets.find(it => it.title === redPacket.title)
        if (!item) {
            this.redPackets = [
                ...this.redPackets,
                redPacket
            ];
        } else {
            this.redPackets = [
                ...this.redPackets.filter(it => it.title !== redPacket.title),
                redPacket
            ];
        }
    }
    /**
     * 中奖时调用
     * @param count 中奖个数
     */
    setCount(count: number, title: string) {
        this.log(`【${title}】开奖成功：${count}`)
        this.count += count;
        const redPacket = this.redPackets.find(it => it.title === title)
        if (redPacket) {
            redPacket.setCount(count)
        }
        sleep(1000)
        this.closeNode && this.closeNode.click()
        this.closeNode = undefined;
    }
    getTotalCount() {
        return this.count;
    }
    /**
     * 打印
     * @param text 
     */
    log(text: string) {
        this.logger && this.logger(text)
    }
    /**
     * 未中奖调用
     * @param text 未中奖说明
     */
    setFail(text: string, title: string) {
        this.log(`【${title}】开奖失败：${text}`)
        const redPacket = this.redPackets.find(it => it.title === title)
        redPacket?.setFail(text)
        sleep(1000)
        this.closeNode && this.closeNode.click()
        this.closeNode = undefined;
    }
    setNoRedPacket() {
        this.noRedPacket = true;
        this.log(`此房间无红包`)
    }
    setMessage(msg: string) {
        if (this.message !== msg) {
            this.message = msg;
            this.log(this.message)
        }
    }
}

class WaitRedOpenVisitor extends CoreVisitor {
    visitNode(node: Ast, ctx: any) {
        super.visitNode(node, ctx)
    }
    redSuccessReg: RegExp = /仅需(.*?)快币/;
    redWaitReg: RegExp = /(.*?)后开奖/;
    visitFrameLayout(node: Ast, ctx: any) {
        if (node.sid === `live_subscribe_draggable_container`) {
            ctx.dbclickNode = node;
        }
        if (node.visibleToUser) {
            return node.children.map(c => c.visit(this, ctx))
        }
    }
    isTitle(node: Ast) {
        return node.sid === `common_red_packet_pop_prepare_reward_desc_view` || node.sid === `title_text_view` || node.sid === `common_red_packet_pop_prepare_reward_desc_view`
    }
    visitTextView(node: Ast, ctx: WaitRedOpenContext | RedPacketContext) {
        if (ctx instanceof WaitRedOpenContext) {
            if (node.text === `退出直播间`) {
                if (node.parent && node.parent.clickable) {
                    node.parent?.click()
                    return;
                }
            }
            if (node.text === `退出`) {
                if (node.parent && node.parent.clickable) {
                    node.parent?.click()
                    return;
                }
            }
            if (node.id.endsWith(`live_audience_count_text`)) {
                ctx.online = parseInt(node.text)
            }
            if (node.sid === `live_red_packet_status_text`) {
                // node.clickRect()
                const clickNode = node.findInParent(c => c.clickable)
                if (clickNode) {
                    ctx.openNode = clickNode;
                    ctx.setOpenTime(node.text)
                } else {
                    ctx.openNode = clickNode;
                    ctx.setOpenTime(node.text)
                }
            }
            if (node.sid === `live_activity_red_packet_display_text_view`) {
                const clickNode = node.findInParent(c => c.clickable)
                if (clickNode) {
                    ctx.openNode = node;
                    ctx.setOpenTime(node.text)
                } else {
                    ctx.openNode = node;
                    ctx.setOpenTime(node.text)
                }
            }
            if (node.id.endsWith(`bottom_line_tips_view`) && this.redSuccessReg.test(node.text)) {
                const parent = node.parent.parent
                const res = parent.textTexts().match(/仅需.*?快币(.*?)快币/)
                if (res && res.length > 0) {
                    const [, count] = res;
                    // 提取红包名称
                    const title = node.root().findOne(n => this.isTitle(n))
                    ctx.setCount(parseInt(count.trim()), title?.text || ``)
                }
                return;
            }
            if (node.id.endsWith(`status_text_view`) && node.text === `很遗憾，本次未中奖`) {
                const title = node.root().findOne(n => this.isTitle(n))
                ctx.setFail(node.text, title?.text || ``)
                return;
            }
            if (node.id.endsWith(`coupon_top_title`) && node.text === `手慢了，补偿一张充值券`) {
                const title = node.root().findOne(n => this.isTitle(n))
                ctx.setFail(node.text, title?.text || ``)
                return;
            }
            if (node.id.endsWith(`empty_desc_text_view`) && node.text === `很遗憾，本次任务失败`) {
                const title = node.root().findOne(n => this.isTitle(n))
                ctx.setFail(node.text, title?.text)
                return;
            }
            if (node.id.endsWith(`live_play_closed_v3_title_text_view`) && node.text === `直播已结束`) {
                ctx.setClose(node.text)
                return;
            }
        }
        if (ctx instanceof RedPacketContext) {
            if (node.sid === `common_red_packet_pop_prepare_reward_desc_view` || node.sid === `title_text_view` || node.sid === `common_red_packet_pop_prepare_reward_desc_view`) {
                ctx.setTitle(node.text)
                return;
            }
            if (node.sid === `live_condition_leee_button_text`) {
                if (this.redWaitReg.test(node.text)) {
                    ctx.setWait(node.text)
                    return;
                }
            }
            if (node.sid === `count_down_text_view`) {
                ctx.subType = `观众包`
                ctx.setPosition(node.bounds.centerX(), node.bounds.centerY())
                return;
            }
            if (node.id && node.id.endsWith(`red_packet_cover_reward_sub_pack_count`) || node.id.endsWith(`live_sec_kill_red_packet_reward_gift_item_tag`)) {
                ctx.redTotal = parseInt(node.text.replace('x', ''))
            }
            if (node.id && node.id.endsWith(`red_packet_cover_reward_usual_count`) || node.id.endsWith(`live_sec_kill_red_packet_pop_prepare_reward_kcoin_view`)) {
                ctx.redCount = parseInt(node.text);
            }
            if (node.id && node.id.endsWith(`red_packet_cover_reward_usual_unit`) || node.id.endsWith(`live_sec_kill_prepare_reward_desc_text_view`)) {
                ctx.redUnit = node.text
            }
        }
    }
    visitProgressBar(node: Ast, ctx: RedPacketContext) {
        if (node.sid === `live_condition_leee_button_text`) {
            if (this.redWaitReg.test(node.text)) {
                ctx.setWait()
                return;
            }
        }
    }
    visitViewPager(node: Ast, ctx: WaitRedOpenContext) {
        if (node.sid === `live_red_packet_container_view_pager`) {
            ctx.setRedCount(node.children.length)
            // 扫描每个包
            node.children.map(c => {
                const redPacket = new RedPacketContext(ctx)
                c.visit(this, redPacket)
                ctx.addRedPacket(redPacket)
            });
            return;
        }
        return node.children.map(c => c.visit(this, ctx))
    }
    visitRelativeLayout(node: Ast, ctx: RedPacketContext) {
        // 参加红包
        if (node.sid === 'action_view' && node.clickable) {
            ctx.setAction(node);
        }
        return node.children.map(c => c.visit(this, ctx))
    }
    visitImageView(node: Ast, ctx: WaitRedOpenContext) {
        if (node.sid === `live_red_packet_container_close_view` && node.clickable) {
            ctx.closeNode = node;
        }
        if (node.sid === `close_view`) {
            ctx.closeNode = node;
        }
        return node.children.map(c => c.visit(this, ctx))
    }
}

export class LiveRoomJoinAndWaitRedOpen {
    /**
     * 设置运行
     * @param runing 
     */
    runing: boolean = true;
    // 进入房间时间
    minJoinTime: number = 27;
    // 开包时间
    minOpenTime: number = 180;
    maxMoneyV: number = 0.5;

    logger: (text: string) => void;
    setRuning(runing: boolean): void {
        this.runing = runing;
    }
    setLogger(logger: (text: string) => void) {
        this.logger = logger;
    }
    getOtherCondiction(that?: any) {
        if (that) return that.isRuning && this.runing;
        return true;
    }
    wait(types: string[] = ['口令'], that?: any) {
        // 在一个房间最多呆10分鬃
        const ctx = new WaitRedOpenContext(types, 1000 * 60 * 3, 1000 * 60 * 3, 1000 * 60 * 2)
        ctx.setTarget(this)
        ctx.setLogger(this.logger)
        ctx.minJoinTime = this.minJoinTime;
        ctx.minOpenTime = this.minOpenTime;
        ctx.maxMoneyV = this.maxMoneyV;
        const visitor = new WaitRedOpenVisitor()
        while (!ctx.isFinish() && this.getOtherCondiction(that)) {
            const root = createRootAst()
            root.visit(visitor, ctx)
            sleep(1000)
        }
        ctx.closeNode && ctx.closeNode.click()
        return ctx;
    }

    auto(type: string[], that?: any) {
        while (this.runing && this.getOtherCondiction(that)) {
            this.wait(type, that)
            swipeUpV3()
        }
    }
}